﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Management.Automation;
using System.Globalization;
using System.Management.Automation.Runspaces;
using System.Collections;
using System.Data;
using System.ComponentModel;
using System.Text;

namespace Powershell_ML
{
    class Const
    {
        public static Command Get_ExchangeServer = new Command("Get-ExchangeServer");
        public static Command Get_MailboxDatabase = new Command("Get-MailboxDatabase");
        public static Command Get_OrganizationConfig = new Command("Get-OrganizationConfig");
        public static Command Get_TransportConfig = new Command("Get-TransportConfig");
        public static Powershell_ML.Famework.IEntry entry = new Powershell_ML.Famework.Powershell_Utility();
    }
    static class Extend 
    {

        public static string Build_Table_By_List(IEnumerable list, params string[] columns)
        {
            if(list != null)
            { 
                var sb = new StringBuilder();
                sb.Append("<table>");
                string TR = "<tr>";
                string ETR = "</tr>";
                string TD = "<td>";
                string ETD = "</td>";
                sb.Append(TR);
                foreach (string col in columns)
                {

                    sb.Append("<th>");
                    sb.Append(col);
                    sb.Append("</th>");

                }
                sb.Append(ETR);
                foreach (var item in list)
                {
                    sb.Append(TR);
                    //todo this should actually make an HTML table, not just get the properties requested
                    foreach (var column in columns)
                    {
                        sb.Append(TD);
                        Object[] Data = null;
                        try
                        {
                            sb.Append(item.GetType().GetProperty(column).GetValue(item, Data));
                            sb.Append(ETD);
                        }
                        catch (Exception) {
                            sb.Append("");
                            sb.Append(ETD);


                        }
                    }
                    sb.Append(ETR);
                }
                sb.Append("</table>");
                return sb.ToString();
            }
            else { return null; }
        }
    }

    class Famework
    {
        public interface IEntry
        {
          
            double Size_Formater(string data);
            Dictionary<string, string> Wanted_Property_Extractor(PSObject list, string[] Property_List);
            bool String_Validation(string value);
            string SecureStringToString(SecureString value);
            SecureString StringToSecureString(string password);
            List<PSPropertyInfo> Property_Creator(PSObject Obj);
            string GetPropertyName<T>(Expression<Func<T>> property);
            string Extract_Property(List<PSPropertyInfo> data, string property);
            string Extract_String_Property(List<PSPropertyInfo> data, string propertyfilter);
            string LocalToUNC(string localpath, int maxLen);
            string TryGetPropertyValue(Dictionary<string,string> Database_Stocker,string Value_Name);
            object Get_MultiValuedProperty(PSObject Object, string filter);
            List<string> Icollection_To_List(object Target);
        }
        /// <summary>
        /// PowerShell Class Extension & Utilities
        /// </summary>
        public class Powershell_Utility :IEntry
        {

            public List<string> Icollection_To_List(object Target)
            {
                List<string> Raw_Data = new List<string>();
                if (Target != null & Target is ICollection)
                {
                    ICollection Collected_Object = (ICollection)Target;
                    foreach (object found in Collected_Object)
                    {
                        if (found != null)
                        {
                            Raw_Data.Add(found.ToString());
                        }
                    }
                }
                return Raw_Data;
            }
            public object Get_MultiValuedProperty(PSObject Object,string filter)
            {
                if(Object != null)
                {
                    foreach(PSProperty property in Object.Properties)
                    {
                        if(property.Name.Contains(filter))
                        {
                            return property.Value;
                        }
                    }
                    return null;
                }
                else
                {
                    return null;
                }
            }
            [DllImport("mpr.dll")]
            static extern int WNetGetUniversalNameA(string lpLocalPath, int dwInfoLevel, IntPtr lpBuffer, ref int lpBufferSize);
            // I think max length for UNC is actually 32,767
            public  string LocalToUNC(string localPath, int maxLen = 2000)
            {
                IntPtr lpBuff;

                // Allocate the memory
                try
                {
                    lpBuff = Marshal.AllocHGlobal(maxLen);
                }
                catch (OutOfMemoryException)
                {
                    return null;
                }

                try
                {
                    int res = WNetGetUniversalNameA(localPath, 1, lpBuff, ref maxLen);

                    if (res != 0)
                        return null;

                    // lpbuff is a structure, whose first element is a pointer to the UNC name (just going to be lpBuff + sizeof(int))
                    return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(lpBuff));
                }
                catch (Exception)
                {
                    return null;
                }
                finally
                {
                    Marshal.FreeHGlobal(lpBuff);
                }
            }

            public double Size_Formater(string data)
            {
                CultureInfo provider = new CultureInfo("en-US");
                double result;
                if(data.ToLower() == "unlimited")
                {
                    result = 0.0;
                }
                else
                {
                    string[] array = data.Split(new char[]
                    {
                    '('
                    });
                    string value = array[1].Replace(" bytes)", "");
                    double num = Convert.ToDouble(value, provider);
                    string value2 = string.Format("{0:0.##}", num / 1048576.0);
                    result = Convert.ToDouble(value2);
                }
                return result;
            }
            public bool String_Validation (string value)
            {
                return string.IsNullOrEmpty(value) || value.Trim().Length == 0;
            }
            public String SecureStringToString(SecureString value)
            {
                IntPtr valuePtr = IntPtr.Zero;
                try
                {
                    valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
                    return Marshal.PtrToStringUni(valuePtr);
                }
                finally
                {
                    Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
                }
            }
            public SecureString StringToSecureString(string password)
            {
                var secureStr = new SecureString();
                if (password.Length > 0)
                {
                    foreach (var c in password.ToCharArray()) secureStr.AppendChar(c);
                }
                return secureStr;
            }
            /// <summary>
            /// Generic PowerShell Property List Creator
            /// </summary>
            /// <param name="Obj Type PSObject"></param>
            /// <returns></returns>
            /// 
            public List<PSPropertyInfo> Property_Creator(PSObject Obj)
            {
                try
                {
                    List<PSPropertyInfo> Found_Data = new List<PSPropertyInfo>();
                    Obj.Properties.ToList().ForEach(x =>
                    {
                        if (x.Value != null & x.IsGettable & x.Name != null)
                        {

                            Found_Data.Add(x);
                        }
                    });
                    return Found_Data;
                }
                catch (Exception) { return null; }
            }
            public Dictionary<string,string> Wanted_Property_Extractor(PSObject list, string[]Property_List)
            {
                try
                {
                    Dictionary<string, string> data = new Dictionary<string, string>();
                    list.Properties.ToList().ForEach(x =>
                    {
                        if (x.Value != null & x.IsGettable & x.Name != null & Property_List.ToList().Contains(x.Name))
                        {
                            data.Add(x.Name.ToString(), x.Value.ToString());

                        }
                    });
                    return data;
                }
                catch (Exception) { return null; }
            }
            public string GetPropertyName<T>(Expression<Func<T>> property)
            {
                var propertyInfo = (property.Body as MemberExpression).Member as PropertyInfo;
                if (propertyInfo == null)
                {
                    throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
                }
                return propertyInfo.Name;
            }
            public string Extract_Property(List<PSPropertyInfo> Database, string Property)
            {
                var Data = from x in Database
                           where x.Name == Property
                           select x.Value;
                return Data.ToString();
            }
            public string Extract_String_Property(List<PSPropertyInfo> Datatable, string propertyfilter)
            {
                try
                {
                    foreach (PSPropertyInfo found in Datatable)
                    {
                        if (found.TypeNameOfValue != null & found.Value != null & found.Name != null)
                        {
                            if (found.Name.ToString().Contains(propertyfilter))
                            {
                                return found.Value.ToString();
                            }
                        }
                    }
                    return string.Empty;
                }

                catch (Exception) { return string.Empty; }
            }
            public string TryGetPropertyValue(Dictionary<string,string> Database_Stocker,string Value_Name)
            {
                if(Database_Stocker != null |Value_Name != null)
                {
                    try
                    {
                        string temp = "";
                        Database_Stocker.TryGetValue(Value_Name, out temp);
                        return temp;
                    }
                    catch { return string.Empty;}
                }
                return string.Empty;
            }
        }
    }
}
